package com.wskeee.ec.core
{
	import com.wskeee.ec.ens;
	import com.wskeee.ec.interfaces.IEComponent;
	import com.wskeee.ec.interfaces.IFocus;
	import com.wskeee.ec.interfaces.IStyle;
	import com.wskeee.ec.interfaces.IToolTipClient;
	import com.wskeee.ec.interfaces.IValidate;
	import com.wskeee.ec.managers.StyleManager;
	import com.wskeee.ec.utils.DisplayObjectUitl;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import flash.utils.getQualifiedSuperclassName;
	
	use namespace ens;
	
	public class EComponent extends Sprite implements IEComponent,IValidate, IStyle, IToolTipClient, IFocus
	{
		public function EComponent()
		{
			super();
			initialize();
			
			invalidateProperties();
			invalidateSize();
			invalidateDisplayList();
		}
		//========================= 初始化 =======================
		//---------------------
		//initialize
		//---------------------
		protected function initialize():void
		{
			EGlobal.componentManager.add(this);
			initEvent();
			initStyle();
			initChildren();
		}
		//---------------------
		//event
		//---------------------
		protected function initEvent():void
		{
			
		}
		//---------------------
		//style
		//---------------------
		protected function initStyle():void
		{
			//override
		}
		//---------------------
		//children
		//---------------------
		/**
		 * 创建子对象，在子类重写 
		 * 
		 */
		protected function initChildren():void
		{
			//override 
		}
		//========================= end =========================
		
		//========================= validate ====================
		/**
		 * commitProperties（）方法主要负责属性值的计算和生效，因此首先执行，因为这些自己算过的值可能用于布局，
		 * 也可能用于显示。这里也可以用来移除不需要的子节点，但是您需要通过标志位来判断子节点是否存在。
		 * 
		 * measure（）方法用于根据组件的内容大小计算组件尺寸。由于尺寸的计算是自下而上的，所组件子元素的大小改变都会隐试的触发此方法。
		 * 
		 * updatedisplayList() 方法用来更新显示列表（Display List）的布局以及渲染。组件的布局是一个自上而下的过程，
 		 * 所以在这个方法里您需要对不仅仅是组件设置布局属性，而且也要对子元素进行相应的调整。这里也是使用 Flash 绘图 API 的好地方。
		 */
		//---------------------
		//validate
		//---------------------
		public function validate():void
		{
			if(isDestoryFlag)return;
			validateProperties();
			validateSize();
			validateDisplayList();
		}
		public function validateNow(manual:Boolean = false):void
		{
			if(manual)
			{
				invalidatePropertiesFlag = true;
				invalidateSizeFlag = true;
				invalidateDisplayListFlag = true;
			}
			validate();
		}
		
		//---------------------
		//invalidateProperties
		//---------------------
		private var invalidatePropertiesFlag:Boolean = false;
		protected function invalidateProperties():void
		{
			if(!invalidatePropertiesFlag)
			{
				invalidatePropertiesFlag = true;
				EGlobal.renderManager.invalidateProperties(this);
			}
		}
		
		public function validateProperties():void
		{
			if(isDestoryFlag)return;
			if(invalidatePropertiesFlag)
			{
				invalidatePropertiesFlag = false;
				commitProperties();
			}
		}
		/**
		 * 确认属性
		 * 
		 */
		protected function commitProperties():void
		{
			//override 
		}
		//---------------------
		//invalidateSize
		//---------------------
		private var invalidateSizeFlag:Boolean = false;
		
		protected function invalidateSize():void
		{
			if(!invalidateSizeFlag)
			{
				invalidateSizeFlag = true;
				EGlobal.renderManager.invalidateSize(this);
			}
		}
		
		public function validateSize():void
		{
			if(isDestoryFlag)return;
			if(invalidateSizeFlag)
			{
				invalidateSizeFlag = false;
				measureSize();
				invalidateDisplayList();
			}
		}
		
		/**
		 * 确认大小，当大小改变时，
		 * 在这里可以判断最终的大小
		 */
		protected function measureSize():void
		{
			//测量确认大小
			measure();
		}
		/**
		 * 测量组件大小，确定		measureWidth,measureHeight 值
		 */
		protected function measure():void
		{
			//由 子类 重写
			measureWidth = 0;
			measureHeight = 0;
		}
		
		//---------------------
		//invalidateDisplayList
		//---------------------
		/**
		 * 无效标志 
		 */
		private var invalidateDisplayListFlag:Boolean = false;
		/**
		 * 无效组件，以便在下一次更新时，render对组件可显示对象重绘 
		 * 
		 */
		protected function invalidateDisplayList():void
		{
			if(!invalidateDisplayListFlag)
			{
				invalidateDisplayListFlag = true;
				EGlobal.renderManager.invalidateDisplayList(this);
			}
		}
		/**
		 * 检查更新，需要更新直接调用 updateDisplayList 执行更新操作
		 * 完毕进入等待下次更新 
		 */
		public function validateDisplayList():void
		{
			if(isDestoryFlag)return;
			if(invalidateDisplayListFlag)
			{
				invalidateDisplayListFlag = false;
				updateDisplayList();
			}
		}
		protected function updateDisplayList():void
		{
			//在这里写组件的更新
		}
		//========================= end =========================
		
		//========================= style =======================
		//---------------------
		//shadow	阴影
		//---------------------
		private var _shadow:Boolean = true;
		public function set shadow(bo:Boolean):void
		{
			_shadow = bo;
			invalidateProperties();
		}
		public function get shadow():Boolean
		{
			return _shadow;
		}
		
		//---------------------
		//border	边框
		//---------------------
		private var _border:Boolean = false;
		public function set border(bo:Boolean):void
		{
			_border = bo;
			invalidateProperties();
		}
		public function get border():Boolean
		{
			return _border;
		}
		//========================= end =========================
		
		
		//========================= IStyle ======================
		protected var styles:Dictionary = new Dictionary();
		public function setStyles(value:Object):void
		{
			for(var i:String in value)
				styles[i] = value[i];
			invalidateProperties();
			invalidateSize();
			invalidateDisplayList();
		}
		
		/**
		 * 刷新组件样式，该操作会让组件重新去获取最新样式从而应用于组件，
		 * 如果组件已经有自身样式将会忽略继承样式 
		 */
		public function reflashStyle():void
		{
			invalidateProperties();
			invalidateSize();
			invalidateDisplayList();
		}
		
		public function setStyle(name:String, value:Object):void
		{
			styles[name] = value;
			invalidateDisplayList();
		}
		
		public function getStyle(name:String):Object
		{
			if(styles.hasOwnProperty(name))
			{
				return styles[name];
			}else
			{
				return getCompStyle(name);
			}
		}
		
		/**
		 * 获取组件继承样式
		 * 在StyleManager里会用以组件类名的样式，
		 * 可以通过传递类名过去把该类所有样式返回
		 * @param styleName	样式名
		 * @return 
		 * 
		 */
		private function getCompStyle(styleName:String):Object
		{
			var _class:Object = this;
			var qcn:String;
			var className:String = getQualifiedClassName(this);
			var styleObject:Object;
			while(true)
			{
				qcn = getQualifiedClassName(_class);
				className = qcn.substr(qcn.indexOf("::")+2);
				styleObject = styleManager.getStyle(className);
				if((styleObject && styleObject.hasOwnProperty(styleName)) || className == "EComponent")
					break;
				//获取父类，获取父类样式，继承父类样式
				_class = getDefinitionByName(getQualifiedSuperclassName(_class));
			} 
			
			//没有样式时使用 全局样式，globa
			if(!styleObject || !styleObject.hasOwnProperty(styleName))
				styleObject = styleManager.getStyle("global");
			return styleObject[styleName];
		}
		
		protected function get styleManager():StyleManager
		{
			return EGlobal.styleManager;
		}
		//========================= end =========================
		
		
		
		//========================= IToolTips ====================
		public function set toolTipClass(value:Class):void
		{
		}
		
		//---------------------
		//toolTip
		//---------------------
		private var _toolTip:String = "";
		/**
		 * 设置提示 
		 * @param value
		 * 
		 */		
		public function set toolTip(value:String):void
		{
			if(_toolTip!=value)
			{
				EGlobal.toolTipManager.registerToolTip(this,_toolTip,value);
				_toolTip = value;
			}
		}
		
		public function get toolTip():String
		{
			return _toolTip;
		}
		//========================= end =========================
		
		
		
		//========================= IFocus ======================
		public function get isFocus():Boolean
		{
			return EGlobal.focusManager.currentFocus == this;
		}
		
		public function setFocus():void
		{
			EGlobal.focusManager.setFocus(this,true);
		}
		//========================= end =========================
		
		
		
		
		
		//========================= act =========================
		public function setActualSize(w:Number,h:Number,sendEvent:Boolean = true):void
		{
			var changed:Boolean = false;
			if(_width!=w)
			{
				_width = w;
				changed = true;
			}
			
			if(_height!=h)
			{
				_height = h;
				changed = true;
			}
			
			if(changed && sendEvent)
			{
				invalidateDisplayList();
				dispatchEvent(new Event(Event.RESIZE));
			}
		}
		
		public function getFullBounds():Rectangle
		{
			return DisplayObjectUitl.getFullBounds(this);
		}
		
		public function removeAllChildren():void
		{
			while(numChildren>0)
				removeChildAt(0);
		}
		
		private var _enabled:Boolean = true;
		/**
		 * 设置启用禁用组件 
		 * @param bo
		 * 
		 */
		public function set enabled(bo:Boolean):void
		{
			_enabled = bo;
			mouseEnabled = mouseChildren = tabEnabled = bo;
			alpha = bo ? 1 : 0.3;
			invalidateProperties();
		}
		
		public function get enabled():Boolean
		{
			return _enabled;
		}
		
		private var isDestoryFlag:Boolean = false;
		public function destory():void
		{
			var child:DisplayObject;
			//销毁所有 子对象
			while(numChildren>0)
			{
				child = getChildAt(0);
				if(child is EComponent)
				{
					EComponent(child).destory();
				}else
				{
					if(child.parent)
						removeChild(child);
				}
			}
			if(parent && parent.contains(this))
				parent.removeChild(this);
			//在组件管理类中删除组件的引用
			EGlobal.componentManager.remove(this);
			isDestoryFlag = true;
		}
		
		//---------------------
		//width & height
		//---------------------
		ens var _width:Number;
		ens var _height:Number;
		override public function set width(value:Number):void
		{
			if(explicitWidth!=value)
			{
				explicitWidth = value;
				invalidateSize();
			}
			if(_width!=value)
			{
				_width = value;
				invalidateProperties();
				invalidateSize();
				dispatchEvent(new Event(Event.RESIZE));
			}
		}
		
		override public function get width():Number
		{
			return _width;
		}
		
		override public function set height(value:Number):void
		{
			if(explicitHeight!=value)
			{
				explicitHeight = value;
				invalidateSize();
			}
			if(_height!=value)
			{
				_height = value;
				invalidateProperties();
				invalidateSize();
				dispatchEvent(new Event(Event.RESIZE));
			}
		}
		
		override public function get height():Number
		{
			return _height;
		}
		//---------------------
		//explicitWidth & explicitHeight
		//---------------------
		/**
		 *  直接、精确宽度，优先于 测量宽度
		 */		
		private var _explicitWidth:Number;
		public function get explicitWidth():Number
		{
			return _explicitWidth;
		}
		public function set explicitWidth(value:Number):void
		{
			if(_explicitWidth==value)return;
			_explicitWidth = value;
			invalidateSize();
			
		}
		/**
		 *  直接、精确高度，优先于 测量高度
		 */	
		private var _explicitHeight:Number;
		public function get explicitHeight():Number
		{
			return _explicitHeight;
		}

		public function set explicitHeight(value:Number):void
		{
			if(_explicitHeight == value)return;
			_explicitHeight = value;
			invalidateSize();
		}

		//---------------------
		//measureWidth & measureHeight
		//---------------------
		/**
		 * 测量宽度 
		 */
		private var _measureWidth:Number;
		public function get measureWidth():Number
		{
			return _measureWidth;
		}
		
		public function set measureWidth(value:Number):void
		{
			_measureWidth = value;
		}
		/**
		 * 测量高度 
		 */		
		private var _measureHeight:Number;
		public function get measureHeight():Number
		{
			return _measureHeight;
		}
		
		public function set measureHeight(value:Number):void
		{
			_measureHeight = value;
		}
		//========================= end =========================
	}
}